import os
import csv
from py2neo import Graph, Node, Relationship, NodeMatcher
import py2neo
from py2neo.database import DatabaseConfig

class KnowledgeGraphBuilder:
    def __init__(self):
        # 设置数据目录路径 - 修改为resource目录下的正确位置
        current_dir = os.path.dirname(os.path.abspath(__file__))
        self.data_dir = os.path.join(current_dir, "..", "data", "课程知识图谱数据")
        print(f"数据目录路径: {self.data_dir}")
        
        # 初始化Neo4j连接
        config = DatabaseConfig.get_neo4j_config()
        self.graph = Graph(config["uri"], auth=config["auth"])
        self.matcher = NodeMatcher(self.graph)

    def build_graph(self):
        """构建知识图谱"""
        print("开始构建知识图谱...")
        
        # 检查数据目录是否存在
        if not os.path.exists(self.data_dir):
            print(f"错误：数据目录不存在: {self.data_dir}")
            print("请确保数据文件位于正确的位置")
            return
        
        # 创建实体节点
        print("创建实体节点...")
        self._create_entities()
        
        # 创建关系
        print("创建关系...")
        self._create_relationships()
        
        print("知识图谱构建完成！")

    def _create_entities(self):
        """创建所有实体节点"""
        # 定义实体文件列表
        entity_files = [
            ("专业.csv", "专业", ["id", "name"]),
            ("专业基本信息.csv", "专业基本信息", ["id", "名字", "简介", "发展历程", "培养目标", "培养规格", "课程体系", "教学条件", "发展前景"]),
            ("课程.csv", "课程", ["id", "name", "xueshi", "jieshao", "jiaoxuedagang", "kechengjibie"]),
            ("课程基本信息.csv", "课程基本信息", ["id", "name", "学时", "先修课程", "课程级别", "介绍"]),
            ("课程内容信息.csv", "课程内容信息", ["id", "name", "教学大纲"]),
            ("课程知识单元.csv", "课程知识单元", ["id", "name"]),
            ("课程知识单元基本信息.csv", "课程知识单元基本信息", ["id", "name"]),
            ("课程知识单元内容信息.csv", "课程知识单元内容信息", ["id", "name"]),
            ("课程知识点.csv", "课程知识点", ["id", "name"]),
            ("课程知识点基本信息.csv", "课程知识点基本信息", ["id", "name"]),
            ("课程知识点内容信息.csv", "课程知识点内容信息", ["id", "name"]),
            ("知识单元.csv", "知识单元", ["id", "name", "缩写"]),
            ("知识单元基本信息.csv", "知识单元基本信息", ["id", "name", "缩写"]),
            ("知识单元内容信息.csv", "知识单元内容信息", ["id", "name"]),
            ("知识点.csv", "知识点", ["id", "name", "缩写", "掌握程度", "重要程度"]),
            ("知识点基本信息.csv", "知识点基本信息", ["id", "name", "缩写", "掌握程度", "重要程度"]),
            ("知识点内容信息.csv", "知识点内容信息", ["id", "name"]),
            ("习题.csv", "习题", ["id", "name", "答案"])
        ]

        for file_name, label, properties in entity_files:
            print(f"处理实体文件: {file_name}")
            file_path = os.path.join(self.data_dir, "实体节点", file_name)
            try:
                # 尝试不同的编码方式
                encodings = ['utf-8', 'gbk', 'gb2312', 'ANSI']
                file_opened = False
                
                for encoding in encodings:
                    try:
                        with open(file_path, 'r', encoding=encoding) as f:
                            reader = csv.reader(f)
                            headers = next(reader)  # 跳过表头
                            for row in reader:
                                # 创建属性字典
                                attrs = {prop: value for prop, value in zip(properties, row)}
                                # 创建节点
                                node = Node(label, **attrs)
                                # 使用merge确保节点唯一性
                                self.graph.merge(node, label, "id")
                            file_opened = True
                            break
                    except UnicodeDecodeError:
                        continue
                
                if not file_opened:
                    print(f"无法打开文件 {file_name}，尝试了所有编码方式")
            except Exception as e:
                print(f"处理文件 {file_name} 时出错: {str(e)}")

    def _create_relationships(self):
        """创建所有关系"""
        # 定义关系文件列表
        relationship_files = [
            ("专业-包含-课程.csv", "专业", "课程", "包含", "所属专业"),
            ("专业-包含-专业基本信息.csv", "专业", "专业基本信息", "包含", "属于"),
            ("课程-包含-课程基本信息.csv", "课程", "课程基本信息", "课程基本信息", "基本信息所属课程"),
            ("课程-包含-课程内容信息.csv", "课程", "课程内容信息", "课程内容信息", "内容信息所属课程"),
            ("课程-包含-知识点.csv", "课程", "知识点", "课程所含知识点", "所属课程"),
            ("课程-包含-知识单元.csv", "课程", "知识单元", "课程所含知识单元", "所属课程"),
            ("课程-前置-课程.csv", "课程", "课程", "前置课程", "后继课程"),
            ("课程-后继-课程.csv", "课程", "课程", "后继课程", "前置课程"),
            ("课程内容信息-包含-课程知识单元.csv", "课程内容信息", "课程知识单元", "课程所含课程知识单元", "课程知识单元所属课程"),
            ("课程内容信息-包含-课程知识点.csv", "课程内容信息", "课程知识点", "课程所含课程知识点", "课程知识点所属课程"),
            ("课程知识单元-包含-课程知识单元基本信息.csv", "课程知识单元", "课程知识单元基本信息", "课程知识单元基本信息", "课程知识单元基本信息所属课程知识单元"),
            ("课程知识单元-包含-课程知识单元内容信息.csv", "课程知识单元", "课程知识单元内容信息", "课程知识单元内容信息", "课程知识单元内容信息所属课程知识单元"),
            ("课程知识单元-包含-课程知识点.csv", "课程知识单元", "课程知识点", "课程知识单元所含知识点", "课程知识点所属课程知识单元"),
            ("课程知识点-包含-课程知识点基本信息.csv", "课程知识点", "课程知识点基本信息", "课程知识点基本信息", "课程知识点基本信息所属课程知识点"),
            ("课程知识点-包含-课程知识点内容信息.csv", "课程知识点", "课程知识点内容信息", "课程知识点内容信息", "课程知识点内容信息所属课程知识点"),
            ("课程知识点内容信息-包含-知识点.csv", "课程知识点内容信息", "知识点", "知识点", "知识点所属课程知识点"),
            ("课程知识单元内容信息-包含-知识单元.csv", "课程知识单元内容信息", "知识单元", "知识单元", "知识单元所属课程知识单元"),
            ("知识单元-包含-知识点.csv", "知识单元", "知识点", "知识点", "知识点所属知识单元"),
            ("知识单元-包含-知识单元基本信息.csv", "知识单元", "知识单元基本信息", "知识单元基本信息", "知识单元基本信息所属知识单元"),
            ("知识单元-包含-知识单元内容信息.csv", "知识单元", "知识单元内容信息", "知识单元内容信息", "知识单元内容信息所属知识单元"),
            ("知识单元-包含-习题.csv", "知识单元", "习题", "所含习题", "考察知识单元"),
            ("知识单元-前置知识单元-知识单元.csv", "知识单元", "知识单元", "前置知识单元", "后继知识单元"),
            ("知识单元-后继知识单元-知识单元.csv", "知识单元", "知识单元", "后继知识单元", "前置知识单元"),
            ("知识点-包含-知识点基本信息.csv", "知识点", "知识点基本信息", "知识点基本信息", "知识点基本信息所属知识点"),
            ("知识点-包含-知识点内容信息.csv", "知识点", "知识点内容信息", "知识点内容信息", "知识点内容信息所属知识点"),
            ("知识点-包含-习题.csv", "知识点", "习题", "所含习题", "考察知识点"),
            ("知识点-前置知识点-知识点.csv", "知识点", "知识点", "前置知识点", "后继知识点"),
            ("知识点-后继知识点-知识点.csv", "知识点", "知识点", "后继知识点", "前置知识点")
        ]

        for file_name, start_label, end_label, rel_type, reverse_rel_type in relationship_files:
            print(f"处理关系文件: {file_name}")
            file_path = os.path.join(self.data_dir, "关系", file_name)
            try:
                # 尝试不同的编码方式
                encodings = ['utf-8', 'gbk', 'gb2312', 'ANSI']
                file_opened = False
                
                for encoding in encodings:
                    try:
                        with open(file_path, 'r', encoding=encoding) as f:
                            reader = csv.reader(f)
                            next(reader)  # 跳过表头
                            for row in reader:
                                if len(row) < 2:
                                    continue
                                # 查找起始节点和结束节点
                                start_node = self.matcher.match(start_label, id=row[0]).first()
                                end_node = self.matcher.match(end_label, id=row[1]).first()
                                
                                if start_node and end_node:
                                    # 创建正向关系
                                    rel = Relationship(start_node, rel_type, end_node)
                                    self.graph.merge(rel, "", "id")
                                    
                                    # 创建反向关系
                                    if reverse_rel_type:
                                        reverse_rel = Relationship(end_node, reverse_rel_type, start_node)
                                        self.graph.merge(reverse_rel, "", "id")
                            file_opened = True
                            break
                    except UnicodeDecodeError:
                        continue
                
                if not file_opened:
                    print(f"无法打开文件 {file_name}，尝试了所有编码方式")
            except Exception as e:
                print(f"处理文件 {file_name} 时出错: {str(e)}")

if __name__ == "__main__":
    builder = KnowledgeGraphBuilder()
    builder.build_graph()
